<?php

namespace app\common\command;

use app\admin\service\addons\ManageService;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use think\facade\Config;
use tmcore\services\addons\AddonApiService;
use tmcore\services\addons\CoreService;
use Exception;
use tmcore\services\addons\TerminalService;
use tmcore\services\addons\UtilService;
use app\common\model\addons\Addons as AddonsModel;
use tmcore\utils\File;

/**
 * 插件命令
 */
class Addon extends Command
{
    protected CoreService $service;

    /**
     * 指令配置
     * @return void
     */
    protected function configure()
    {
        // 指令配置
        $this->setName('addon')
            ->setDescription('插件命令行')
            ->addArgument('key', Argument::REQUIRED, '插件标识')
            ->addArgument('action', Argument::REQUIRED, 'install|uninstall|publish|info|clear_download|clear_cache');
    }

    /**
     * 执行指令
     * @param Input $input
     * @param Output $output
     * @return bool
     */
    protected function execute(Input $input, Output $output): bool
    {
        try {
            $key = $input->getArgument('key');
            if(!$key) throw new Exception('插件标识参数为空!');

            $action = $input->getArgument('action') ?: 'info';
            if (!in_array($action, ['install', 'uninstall', 'publish', 'info', 'clear_download', 'clear_cache'])) {
                throw new Exception('Invalid argument action:$action, Expected install|uninstall|publish|info|clear_download|clear_cache');
            }

            $this->service = (new CoreService($key));

            switch ($action) {
                case 'install': // 安装插件
                    $this->install_addon($key, $output);
                    break;
                case 'uninstall': // 删除插件
                    $this->uninstall_addon($key, $output);
                    break;
                case 'info': // 插件信息
                    $info = $this->service->getInfo();
                    $output->writeln(json_encode($info, 320));
                    break;
                case 'publish': // 发布插件
                    $this->publish_addon($key, $output);
                    break;
                case 'clear_download': // 清空下载目录
                    $this->del_download_dir($key, $output);
                    break;
                case 'clear_cache': // 清理缓存
                    $this->service->clearCache();
                    break;
                default:
                    throw new Exception('没找到“' . $action . '”相关命令!');
            }

            $output->writeln("Successful");
            return true;
        } catch ( Exception $e ) {
            $output->writeln("Failed: " . $e->getMessage());
            return false;
        }
    }

    /**
     * 安装插件
     * @param string $key
     * @param Output $output
     * @return void
     */
    private function install_addon($key, Output $output) {

        $count = AddonsModel::where(['identify' => $key])->count();
        if($count) throw new Exception('插件已安装，不可重复安装');

        $user_token = AddonApiService::user_token();
        if(!$user_token) throw new Exception('请先登录账号');

        $addon_row = AddonApiService::get_addons_info($key);
        if(!$addon_row) throw new Exception('查询不到插件信息');
        if(empty($addon_row['is_buy'])) throw new Exception('插件未购买');

        $result = ManageService::downloadAddon(['identify' => $key, 'version' => $addon_row['version']]);
        if (true === $result) {
            $output->writeln('下载软件包成功');
            // 安装插件
            $this->service->install(['identify' => $key, 'version' => $addon_row['version']]);
            $output->writeln('安装插件成功');
            // 发布插件
            $this->publish_addon($key, $output);
        } else {
            throw new Exception(ManageService::getError());
        }
    }

    /**
     * 删除插件
     * @param $key
     * @param Output $output
     * @return void
     */
    private function uninstall_addon($key, Output $output) {
        $row = AddonsModel::where(['identify' => $key])->findOrEmpty();
        if(!$row) throw new Exception('插件未安装');

        // 获取插件依赖
        $depends = ManageService::getDepends(['identify' => $key]);

        $depends_data = [];
        foreach ($depends as $depend) {
            $depends_data[$depend['module'] . '_' . $depend['type']][$depend['setting']][$depend['depend']] = $depend['version'];
        }
        $output->writeln('获取依赖成功');
        // 卸载插件
        $this->service->uninstall(['uninstall_reserve_depend_list' => $depends_data]);
        $output->writeln('卸载插件成功');
        // 发布插件
        $this->publish_addon($key, $output);
    }

    /**
     * 发布插件
     * @param string $key
     * @param Output $output
     * @return void
     * @throws Exception
     */
    private function publish_addon($key, Output $output) {

        // 获取执行命令
        $execute_commands = UtilService::getExecCommands($key);
        $terminalService = (new TerminalService());
        $root_path = app()->getRootPath();
        $sys_path = dirname($root_path) . DIRECTORY_SEPARATOR;
        $command_config = Config::get('addons.terminal_commands');

        $output->writeln('开始发布插件...');

        foreach($execute_commands as $command) {
            $info = $terminalService->getCommandInfo($command);
            $output->writeln('> cd ' . $info['dir']);
            $output->writeln('> ' . $info['command']);
            // 执行命令
            $res = (new TerminalService())->getExecResult([
                'command' => $info['command'],
                'dir' => $info['dir'],
            ]);
            if($res) {
                if(isset($res['status']['exitcode']) && $res['status']['exitcode'] == 0) {
                    $output->writeln($command . ' 命令执行成功');
                    $build_result = UtilService::getBuildDirs($command);
                    if($build_result) {
                        $module = $build_result['command_arr'][0];
                        $dist_file_arr = $build_result['dist_file_arr'];
                        $to_file_arr = $build_result['to_file_arr'];

                        // 检测编译文件
                        foreach ($dist_file_arr as $file) {
                            if (!file_exists($file)) throw new Exception('编译文件不存在,文件路径:'. $file);
                        }

                        try {
                            // 删除公共编译目录文件
                            foreach ($to_file_arr as $file) {
                                if(is_dir($file)) {
                                    File::del_file($file);
                                } else {
                                    if(file_exists($file)) @unlink($file);
                                }
                            }

                            for($i = 0; $i < count($to_file_arr); $i++) {
                                // 转移文件
                                if(!File::recursiveMove($dist_file_arr[$i], $to_file_arr[$i])) {
                                    throw new \Exception('转移编译文件失败,文件路径:'. $to_file_arr[$i]);
                                }
                            }

                            // 删除编译目录
                            File::del_file($sys_path . $module. '/dist');

                            $output->writeln($module . ' 模块发布编译文件成功');

                        } catch (\Exception $e) {
                            // 异常时还原备份的前端编译文件
                            $backup_dir = $root_path . 'data/backup' . DIRECTORY_SEPARATOR;
                            if($module == 'uniapp') $module = 'app';
                            if (is_dir($backup_dir . $module)) {
                                File::copy_dir($backup_dir . $module, $root_path . 'public/' . $module);
                            }
                            throw new Exception($e->getMessage());
                        }
                    }
                } else {
                    // 针对 composer 权限问题兼容
                    if($command == 'server.install' && empty($command_config['env']['composer_home'])) {
                        $output->writeln('composer 命令执行失败，请手动执行发布或配置COMPOSER_HOME环境变量');
                        continue;
                    }

                    throw new Exception('命令执行失败,请查看错误信息:' . $res['result']);
                }
            } else {
                throw new Exception('命令执行失败');
            }
        }
        $output->writeln('发布插件成功');
    }

    /**
     * 清空下载目录
     * @param Output $output
     * @return void
     * @throws Exception
     */
    private function del_download_dir($key, Output $output)
    {
        $root_path = app()->getRootPath();
        $backup_dir = $root_path . 'data/download/addons' . DIRECTORY_SEPARATOR . $key . DIRECTORY_SEPARATOR;

        File::del_dir($backup_dir);

        $output->writeln('清空插件下载目录成功,目录路径:' . $backup_dir);
    }

}